# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.


from odoo import api, fields, models, _

import datetime
from dateutil.relativedelta import relativedelta

from odoo.addons import decimal_precision as dp

    
class AccountSubAccount(models.Model):
    
    _name = "account.sub.account"
    _description = "Account Sub Account"
    _order = "account_id,code"
    
    account_id = fields.Many2one('account.account', string='Account', required=True, index=True,
        ondelete="cascade", domain=[('deprecated', '=', False)], default=lambda self: self._context.get('account_id', False))

    account_code = fields.Char(related='account_id.code')
    account_name = fields.Char(related='account_id.name')


    code = fields.Char(string='Sub Code')
    name = fields.Char(string='Sub Name')
    
    sub_type = fields.Selection(store=True, related='account_id.sub_type' )

    partner_id = fields.Many2one('res.partner', string='Partner')
    product_id = fields.Many2one('product.product', string='Product')
    journal_id = fields.Many2one('account.journal', string='Journal')
    analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', index=True)
    
    def find_create(self, account_id,journal_id=None, partner_id=None, product_id=None, 
                          analytic_account_id=None,analytic_tag_id=None ):
    
        #call by model 'account.move.line'
        if account_id.sub_type == 'none':
            return None

        domain2 = {
               'bank':    ('journal_id',journal_id ),
               'partner': ('partner_id',partner_id ),
               'product': ('product_id',product_id ),
               'analytic': ('analytic_account_id',analytic_account_id ),
               #'tag': ( 'analytic_tag_id',self.analytic_tag_id ),

        }[account_id.sub_type]
        
        domain = [
            ('account_id','=',account_id.id),
            (domain2[0],'=', domain2[1].id)
        ]
        
        sub = self.search(domain, limit=1)
        if sub:
            return sub

        vals = {
            'account_id': account_id.id,
        }
        
        if account_id.sub_type == 'bank':
            vals.update({
                'journal_id': journal_id.id, 
                'code': journal_id.code, 
                'name':journal_id.name })
        
        elif account_id.sub_type == 'partner':
            vals.update( {'partner_id': partner_id.id, 
                           'code': partner_id.ref, 
                           'name':partner_id.name })

        elif account_id.sub_type == 'product':
            vals.update({'product_id': product_id.id, 
                            'code': product_id.code, 
                            'name':product_id.name })
        elif account_id.sub_type == 'analytic':
            vals.update({'analytic_account_id': analytic_account_id.id, 
                           'code': analytic_account_id.code, 
                           'name':analytic_account_id.name })
        #elif account_id.sub_type == 'tag':
        #    vals.update({'analytic_tag_id': analytic_tag_id.id, 
        #                   'code': analytic_tag_id.code, 
        #                   'name':analytic_tag_id.name })
        else:
            return None
        
        return self.create(vals)


class AccountMove(models.Model):
    _inherit = "account.move"

    @api.depends('number_cn')
    def _compute_name_cn(self):
        for rec in self:
            rec.name_cn = '记-' + str(rec.number_cn)
    
    def _get_default_number_cn(self):
        return self.get_number_cn()

    @api.model
    def get_number_cn(self):
        numbers = self.search([]).mapped('number_cn')
        number = numbers and max(numbers) or 0
        return number + 1
    
    
    name_cn = fields.Char(string='China Full Number', store=True, compute='_compute_name_cn' )
    number_cn = fields.Integer(string='China Number', required=True, copy=False, default=_get_default_number_cn)
    
    attachment_count = fields.Integer( default=0 )

    @api.model
    @api.returns('self', lambda value: value.id)
    def carryover_additional_tax(self, line_ids, tax_ids, journal_id=None, debit_account_id=None ):
        lines_obj = self.line_ids.browse(line_ids)
        tax_ids_obj = self.env['account.tax'].browse(tax_ids)
        
        amount = sum( lines_obj.mapped('balance') )
        
        if amount<=0:
            return self.env['account.move']
        
        taxes = tax_ids_obj.compute_all(amount)
        
        lines = [{
            'account_id': tax['account_id'],
            'name': tax['name'],
            'debit': 0,
            'credit': tax['amount'],
        
        }for tax in taxes['taxes']]

        if journal_id:
            journal = self.env['account.journal'].browse(journal_id)
        else:
            journal = self.env['account.journal'].search([
                ('internal_code','=','tax'), ('type','=','tax')],limit=1)
   
        if not debit_account_id:
            debit_account_id = journal.default_debit_account_id.id
            
        lines.append({
            'account_id': debit_account_id,
            'name': '附加税',
            'debit': sum( [ tax['amount'] for tax in taxes['taxes']] ) ,
            'credit': 0 ,
        })
        
        lines = [ (0, 0, line) for line in lines ]

        vals = {
            'journal_id' : journal.id,
            #'date': this_month_last_day,
            'ref': '附加税',
            'line_ids': lines,
        }
        
        return self.create(vals)

    @api.model
    @api.returns('self', lambda value: value.id)
    def carryover_vat(self, line_ids, journal_id=None, debit_account_id=None, credit_account_id=None ):
        lines_obj = self.line_ids.browse(line_ids)

        reconcile = self.env['account.full.reconcile'].create({})
        
        for ln in lines_obj:
            ln.full_reconcile_id = reconcile

        lines = [{
            'account_id': aml.account_id.id,
            'name': aml.name,
            'debit': aml.credit,
            'credit': aml.debit,
            'full_reconcile_id': reconcile.id,
            
        }for aml in lines_obj ]

        delta = sum( lines_obj.mapped('balance') )
        
        if journal_id:
            journal = self.env['account.journal'].browse(journal_id)
        else:
            journal = self.env['account.journal'].search([
                ('internal_code','=','vat'), ('type','=','tax')],limit=1)
        
        if not debit_account_id:
            debit_account_id = journal.default_debit_account_id.id
        
        if not credit_account_id:
            credit_account_id = journal.default_credit_account_id.id
        
        if(delta):
            lines.append({
                'account_id': delta > 0 and debit_account_id or credit_account_id,
                'name': delta > 0 and '未交税额' or '未抵扣的进项税',
                'debit': delta > 0 and delta or 0,
                'credit': delta < 0 and -delta or 0,
            })
        
        lines = [ (0, 0, line) for line in lines ]

        vals = {
            'journal_id' : journal.id,
            #'date': this_month_last_day,
            'ref': '结转增值税',
            'line_ids': lines,
        }
        
        return self.create(vals)


    @api.model
    @api.returns('self', lambda value: value.id)
    def carryover_profit(self, date, line_ids=None):
        date0 = datetime.datetime.strptime(date,'%Y-%m-%d').date()
        this_month_1st_day = datetime.date(date0.year, date0.month,1)
        next_month_1st_day = this_month_1st_day + relativedelta(months=1)
        this_month_last_day = next_month_1st_day - relativedelta(days=1)

        if line_ids:
            lines = self.line_ids.browse(line_ids)
        
        elif line_ids == None:
            lines = self.line_ids.search([
                ('move_id.state','=','posted'),
                #('account_id.internal_group','in', ['income','expense' ]),
                ('account_id.tag_ids.type', '=', 'profit' ),
                ('full_reconcile_id','=',False),
                ('date','>=',this_month_1st_day),
                ('date','<',next_month_1st_day),
            ])
            
        else:
            return self.env['account.move']
        
        return self._carryover_profit(this_month_last_day, lines )

    @api.model
    def _carryover_profit(self, this_month_last_day, src_lines):
        profit_journal = self.env['account.journal'].search([('type','=','profit')],limit=1)
        
        lines = [{
            'account_id': aml.account_id.id,
            'name': aml.name,
            'debit': aml.credit,
            'credit': aml.debit,
        }for aml in src_lines ]
        
        profit = sum( src_lines.mapped('balance') )
        
        profit_account_id = profit_journal.default_credit_account_id
        
        lines.append({
            'account_id': profit_account_id.id,
            'name': '结转利润',
            'debit': profit>=0 and profit or 0.00,
            'credit': profit<0 and -profit or 0.00,
        })
        
        
        lines = [ (0, 0, line) for line in lines ]
        
        vals = {
            'journal_id' : profit_journal.id,
            'date': this_month_last_day,
            'ref': '结转利润',
            'line_ids': lines,
        }
        
        profit_move_id = self.create(vals)
        
        dest_lines= profit_move_id.line_ids.filtered(
            lambda item: item.account_id != profit_account_id )
        
        all_lines = src_lines | dest_lines

        reconcile = self.env['account.full.reconcile'].create({})
        
        for ln in all_lines:
            ln.full_reconcile_id = reconcile
        
        
        return profit_move_id

class AccountMoveLine(models.Model):
    _inherit = "account.move.line"

    #account_id = fields.Many2one('account.account', string='Account', required=True, index=True, ondelete="cascade", domain=[('deprecated', '=', False)], default=lambda self: self._context.get('account_id', False))
    #analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', index=True)
    #partner_id = fields.Many2one('res.partner', string='Partner', ondelete='restrict')
    #product_uom_id = fields.Many2one('uom.uom', string='Unit of Measure')
    #product_id = fields.Many2one('product.product', string='Product')
    #analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tags')

    """
    # For detail account
    analytic_tag_id = fields.Many2one('account.analytic.tag', string='Analytic Tags',
        store=True,compute='_compute_analytic_tag', help='For detail Account')

    @api.depends('analytic_tag_ids')
    def _compute_analytic_tag(self):
        for line in self:
            line.analytic_tag_id = line.analytic_tag_ids.filtered(
                lambda item: item.type=='detail')
    """

    sequence = fields.Integer(help='Used to order Move line in the move view', default=10)

    sub_account_id = fields.Many2one('account.sub.account', string='Sub Account', 
                                      ondelete='restrict', index=True )

    sub_account_id_is_auto = fields.Boolean( default=True,
        help="Technical field used to know if the sub_account_id field has been set auto.")

    @api.model
    def create(self, vals):
        return create2(AccountMoveLine,self, vals)

    @api.multi
    def write(self, vals):
        return write2(AccountMoveLine,self, vals)

    def _set_sub_account(self):
        _set_sub_account(self)

    @api.multi
    def unlink(self):
        full_reconcile_ids = self.mapped('full_reconcile_id')
        result = super(AccountMoveLine, self).unlink()
        
        if result:
            full_reconcile_ids.unlink()
        
        return result


def create2(cls, self, vals ):

        """
        if not set sub_account_id: 
            sub_account_id is auto computed from partner_id, product_id,...
        else:
            sub_account_id is manual to set
            if sub_account_id == 0:
                sub_account_id is set null
            else sub_account_id > 0:
                sub_account_id is set with a ref
        
        """
        
        
        sub_account_id = vals.get('sub_account_id',None)
        
        if sub_account_id == None:
            pass
        else:
            vals['sub_account_id_is_auto'] = False
            if sub_account_id == 0:
                del vals['sub_account_id']
            
        
        move_line = super(cls,self).create(vals)
        if move_line.sub_account_id_is_auto:
            ret = move_line._set_sub_account()
        
        return move_line

    
def write2(cls, self, vals ):
        """
        if sub_account_id in vals:
            this is to set sub_account_id, we do nothing else
        else:
            this is modify other field, so to check sub_account_id_is_auto and set sub_account_id
        """
        sub_account_id = vals.get('sub_account_id', None)
        if sub_account_id == 0:
            vals['sub_account_id'] = None
        
        ret = super(cls,self).write(vals)
        for rec in self:
            if rec.sub_account_id_is_auto:
                if sub_account_id == None:
                    rec._set_sub_account()
        
        return ret

def _set_sub_account(self):
        
        if self.account_id.sub_type == 'none':
            if self.sub_account_id:
                self.sub_account_id = 0
            return None
        
        sub_model = self.env['account.sub.account']
        
        kwargs = {
            'bank':    { 'journal_id': self.journal_id },
            'partner': { 'partner_id': self.partner_id },
            'product': { 'product_id': self.product_id },
            'analytic': { 'analytic_account_id': self.analytic_account_id },
            #'tag': { 'analytic_tag_id': self.analytic_tag_id },
        }[self.account_id.sub_type]
        
        sub_account_id = sub_model.find_create( self.account_id, **kwargs )
        
        self.sub_account_id = sub_account_id and sub_account_id or 0
        return None

